/*
 * Copyright 2012 Alain Pannetrat (L1L1@gmx.com)
 * 
 * This file is part of cookie-miner.
 * 
 * cookie-miner is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * cookie-miner is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License 
 * along with cookie-miner. If not, see http://www.gnu.org/licenses/.
 *
 * @version: $Id$
 *
 */
#include <string>
#include "http_packet.h"

class HttpClient : private Uncopyable {
	public:
		HttpClient(const std::string& host);

		bool prepare(const std::string& method, 
			     const std::string& request_uri);
		
		bool request_header(const std::string& header,
				    const std::string& value);
		
		bool send(const std::string& data="");
		
		int status() const;

		const std::string& status_text() const;
		
		const HttpPacket::Headers& all_response_headers() const;
		
		const std::string& response_header(const std::string& header) const;

		std::string response_text() const; 

		~HttpClient();
	private:
		std::string		 _host;
		BufferInOutSocket	*_bio;
		HttpPacket 		*_request;
		HttpPacket 		*_response;
};

static const std::string empty_string;

HttpClient::HttpClient(const std::string& host) : 
	_host(host),
	_bio(NULL),
	_request(NULL),
	_response(NULL)
{
	/* void */
}

HttpClient::~HttpClient()
{
	if (_bio) delete _bio;
	if (_request) delete _request;
	if (_response) delete _response;
}

bool HttpClient::prepare(const std::string& method, 
		         const std::string& request_uri)
{
	if (_host.size()==0) return false;

	if (_bio==NULL)
	{
		int fd = tcp_connect(_host.c_str());

		if (fd<0) return false;

		if ((_bio=BufferInOutSocket::create(fd))==NULL) return false;
	}

	if (_request) 
	{
		delete _request;
		_request = NULL;
	}

	if (_response) 
	{
		delete _response;
		_response = NULL;
	}

	_request = new HttpPacket();
	_request->headline().set(method,request_uri,"HTTP/1.1");
	_request->headers().set("Host",_host);
	_request->headers().set("User-Agent","http_client_cc/0.1");
	return true;
}

bool HttpClient::request_header(const std::string& header,
		  		const std::string& value)
{
	if (_request==NULL) return false;
	_request->headers().set(header,value);
	return true;
}

bool HttpClient::send(const std::string& data)
{
	if (_request==NULL) return false;
	_request->headers().set("Content-Length",data.size());
	_request->content_add(data);
	
	if (!_request->headline().write_out(_bio) ||
	    !_request->headers().write_out(_bio) ||
	    !_request->content_write_out(_bio) ||
	    !_bio->write_flush())
		return false;

	_response = new HttpPacket();
	
	return 	_response->headline().read_in(_bio) &&
	       	_response->headers().read_in(_bio) &&
		_response->content_read_in(_bio);		
}
		
int HttpClient::status() const
{
	if (_response==NULL) return 0;
	return atoi(_response->headline().part(1).c_str());
}

const std::string& HttpClient::status_text() const
{
	if (_response==NULL) return empty_string;
	return _response->headline().part(2);
}
		
const HttpPacket::Headers& HttpClient::all_response_headers() const
{
	return _response->headers();
}
		
const std::string& HttpClient::response_header(const std::string& header) const
{
	if (_response==NULL) return empty_string;
	return _response->headers().get(header);
}

std::string HttpClient::response_text() const
{
	if (_response==NULL) return empty_string;
	std::string s((char*)_response->content_get(),_response->content_length());
	return s;
}

#include <iostream>
int main()
{
    HttpClient client("localhost:8080");

    while (1)
    {
	if (!client.prepare("GET","/"))
	    std::cout << "open failed" << std::endl;

	if (!client.send())
	    std::cout << "send failed" << std::endl;

	std::cout << "STATUS: " << client.status() << " " << client.status_text() << std::endl;

	std::cout << "END" << std::endl; 

	sleep(3);
    }
}

